package cn.teawooo.tree.mvnpro;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;

import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;

import cn.teawooo.tree.TreeIterator;
import cn.teawooo.tree.mvnpro.project.MvnModule;
import cn.teawooo.tree.string.StringNode;
import cn.teawooo.tree.string.StringParser;
import cn.teawooo.tree.string.StringTree;

/**
 * 功能描述：
 * 
 * @author teawooo <long1795@gmail.com>
 * @time 2013年8月26日 下午2:59:58
 */
public class MvnProject extends MvnTree {
    private String templatePath;
    private String outputRootPath;
    private boolean doGenerate = false;

    public MvnProject(String templatePath, String outputRootPath) {
        this.templatePath = templatePath;
        this.outputRootPath = outputRootPath;
    }

    /**
     * 从模板生成MVN项目结构树
     * 
     * @param pattern 模板
     * @param doGenerate 是否生成目录（若为false,仅打印目录结构）
     */
    public void fromPattern(String pattern, boolean doGenerate) {
        StringTree st = new StringParser(pattern).parseTree();
        st.iterate(new TreeIterator<StringNode>() {
            @Override
            public void doIterateImpl(StringNode node, int currLevel) {
                if (currLevel == 0) {
                    root = new MvnNode(node.getData(), new MvnModule(node.getData()));
                } else {
                    MvnNode n = getNode(node.getParent().getData());
                    if (n != null) {
                        n.fastGrown(node.getData());
                    } else {
                        logger.warn("No node named [{}]", node.getParent().getData());
                    }
                }
            }
        });

        generateProject(doGenerate);
    }

    /**
     * 生成MVN项目结构树
     * 
     * @param doGenerate 是否生成目录（若为false,仅打印目录结构）
     */
    public void generateProject(boolean doGenerate) {
        this.doGenerate = doGenerate;
        this.iterate();
    }

    @Override
    protected TreeIterator<MvnNode> getDefaultIterator() {
        if (!doGenerate) {
            return super.getDefaultIterator();
        }
        return new TreeIterator<MvnNode>() {
            @Override
            public void doIterateImpl(MvnNode node, int currLevel) {
                mkProjectDirs(node);
                generatePom(node);
            }
        };
    }

    private void generatePom(MvnNode node) {
        VelocityContext vc = new VelocityContext();
        vc.put("scmConn", "scm:svn:svn://....../trunk/....../");
        vc.put("tagBase", "scm:svn:svn://....../tags/....../");
        vc.put("module", node.getData());
        vc.put("children", node.getChildren());
        if (node.getParent() != null) {
            vc.put("parent", node.getParent().getData());
        }

        String pomTemplatePath = templatePath + (templatePath.endsWith(File.separator) ? "pom.xml" : File.separator + "pom.xml");
        String pomOutputPath = node.getNodePath(outputRootPath) + "pom.xml";
        FileWriter pomOut = null;
        InputStreamReader inputStreamReader = null;
        try {
            inputStreamReader = new InputStreamReader(new FileInputStream(pomTemplatePath));
            pomOut = new FileWriter(new File(pomOutputPath));

            Velocity.init();
            VelocityEngine ve = new VelocityEngine();
            ve.evaluate(vc, pomOut, "velocity", inputStreamReader);
        } catch (Exception e) {
            logger.error(e, e.getMessage());
        } finally {
            try {
                if (pomOut != null) {
                    pomOut.close();
                }
                if (inputStreamReader != null) {
                    inputStreamReader.close();
                }
            } catch (Exception e) {
                logger.error(e, e.getMessage());
            }
        }
    }

    private void mkProjectDirs(MvnNode node) {
        String outputPath = node.getNodePath(outputRootPath);
        switch (node.getData().getPackaging()) {
        case pom:
            mkdirs(outputPath);
            break;
        case jar:
            mkSrcDir(outputPath, node.getData().getGroupId(), node.getData().getName());
            break;
        case war:
            mkSrcDir(outputPath, node.getData().getGroupId(), node.getData().getName());
            String testResourcesPath = getPath(outputPath, "src", "main", "webapp", "WEB-INF");
            mkdirs(testResourcesPath);

            String webTemplatePath = templatePath + (templatePath.endsWith(File.separator) ? "web.xml" : File.separator + "web.xml");
            copyFile(webTemplatePath, testResourcesPath);
            break;
        }
    }

    private void copyFile(String src, String target) {
        try {
            File srcFile = new File(src);
            FileInputStream input = null;
            FileOutputStream output = null;
            try {
                input = new FileInputStream(srcFile);
                output = new FileOutputStream(target + (srcFile.getName()).toString());
                byte[] b = new byte[1024 * 5];
                int len;
                while ((len = input.read(b)) != -1) {
                    output.write(b, 0, len);
                }
                output.flush();
            } finally {
                if (output != null) {
                    output.close();
                }
                if (input != null) {
                    input.close();
                }
            }
        } catch (Exception e) {
            logger.error(e, e.getMessage());
        }
    }

    private void mkSrcDir(String tmp, String group, String name) {
        mkdirs(tmp, "src", "main", "java", group.replaceAll("\\.", "\\" + File.separator), name);
        mkdirs(tmp, "src", "main", "resources");
        mkdirs(tmp, "src", "test", "java", group.replaceAll("\\.", "\\" + File.separator), name, "test");

        String testResourcesPath = getPath(tmp, "src", "test", "resources");
        mkdirs(testResourcesPath, "META-INF");
        String log4jTemplatePath = templatePath + (templatePath.endsWith(File.separator) ? "log4j.xml" : File.separator + "log4j.xml");
        copyFile(log4jTemplatePath, testResourcesPath);
    }

    private void mkdirs(String partentPath, String... subPaths) {
        File f = new File(getPath(partentPath, subPaths));
        if (!f.isDirectory()) {
            f.mkdirs();
        }
    }

    private String getPath(String partentPath, String... subPaths) {
        StringBuffer path = new StringBuffer(partentPath);
        if (!partentPath.endsWith(File.separator)) {
            path.append(File.separator);
        }
        for (String p : subPaths) {
            path.append(p).append(File.separator);
        }
        return path.toString();
    }

}
